#pragma once

#ifndef _Octree_h_
#define _Octree_h_

#include "TreeBase.h"
#include "../d3d/d3dUtility.h"

#include <vector>

namespace Framework {

using namespace std;

template<typename T>
class Octree : public TreeBase<T> {
public:
    Octree(d3d::BoundingBox* boundingBox, FLOAT treshold, const Octree<T>* parent);
    virtual ~Octree(void);
protected:
    virtual TreeBase<T>* Create(FLOAT minX, FLOAT minY, FLOAT minZ, FLOAT maxX, FLOAT maxY, FLOAT maxZ) const;
};


template<typename T>
Octree<T>::Octree(d3d::BoundingBox* boundingBox, FLOAT treshold, const Octree<T>* parent) :
        TreeBase<T>(boundingBox, treshold, parent) {
    this->children = (vector<TreeBase*>*)new vector<Octree*>();

    TreeBase<T>* octree = NULL;
    this->item = NULL;
    FLOAT minX = this->boundingBox->_min.x;
    FLOAT minY = this->boundingBox->_min.y;
    FLOAT minZ = this->boundingBox->_min.z;
    FLOAT maxX = this->boundingBox->_max.x;
    FLOAT maxY = this->boundingBox->_max.y;
    FLOAT maxZ = this->boundingBox->_max.z;
    FLOAT halfX = minX + (maxX - minX) / 2;
    FLOAT halfY = minY + (maxY - minY) / 2;
    FLOAT halfZ = minZ + (maxZ - minZ) / 2;

    this->boundingSphere = new d3d::BoundingSphere();
    this->boundingSphere->_center.x = halfX;
    this->boundingSphere->_center.y = halfY;
    this->boundingSphere->_center.z = halfZ;
    this->boundingSphere->_radius = D3DXVec3Length(&(this->boundingBox->_max - this->boundingBox->_min));

    if (maxX - minX < treshold || maxY - minY < treshold || maxZ - minZ < treshold) {
        return;
    }

    octree = this->Create(minX, minY, minZ, halfX, halfY, halfZ);
    this->children->push_back(octree);
    octree = this->Create(halfX, minY, minZ, maxX, halfY, halfZ);
    this->children->push_back(octree);
    octree = this->Create(minX, halfY, minZ, halfX, maxY, halfZ);
    this->children->push_back(octree);
    octree = this->Create(halfX, halfY, minZ, maxX, maxY, halfZ);
    this->children->push_back(octree);
    octree = this->Create(minX, minY, halfZ, halfX, halfY, maxZ);
    this->children->push_back(octree);
    octree = this->Create(halfX, minY, halfZ, maxX, halfY, maxZ);
    this->children->push_back(octree);
    octree = this->Create(minX, halfY, halfZ, halfX, maxY, maxZ);
    this->children->push_back(octree);
    octree = this->Create(halfX, halfY, halfZ, maxX, maxY, maxZ);
    this->children->push_back(octree);
}

template<typename T>
Octree<T>::~Octree(void) {
}

template<typename T>
TreeBase<T>* Octree<T>::Create(FLOAT minX, FLOAT minY, FLOAT minZ, FLOAT maxX, FLOAT maxY, FLOAT maxZ) const {
    d3d::BoundingBox* boundingBox = new d3d::BoundingBox();
    boundingBox->_min.x = minX;
    boundingBox->_min.y = minY;
    boundingBox->_min.z = minZ;
    boundingBox->_max.x = maxX;
    boundingBox->_max.y = maxY;
    boundingBox->_max.z = maxZ;

    return new Octree<T>(boundingBox, this->treshold, this);
}

}

#endif
